package com.ivy.parser.utils;

import com.yomahub.liteflow.builder.el.ELWrapper;
import com.yomahub.liteflow.builder.el.ThenELWrapper;
import com.yomahub.liteflow.builder.el.WhenELWrapper;

public class FlowConvertELUtil {

    public static boolean isThenELWrapper(ELWrapper elWrapper){
        if(elWrapper instanceof ThenELWrapper){
            return true;
        }
        return false;
    }

    public static boolean isWhenELWrapper(ELWrapper elWrapper){
        if(elWrapper instanceof WhenELWrapper){
            return true;
        }
        return false;
    }

    public static void convert(ELWrapper wrapper,ELWrapper elWrapper){
        if(wrapper instanceof ThenELWrapper){
            ThenELWrapper thenELWrapper = (ThenELWrapper) wrapper;
            thenELWrapper.then(elWrapper);
        }else if(wrapper instanceof WhenELWrapper){
            WhenELWrapper whenELWrapper = (WhenELWrapper) wrapper;
            whenELWrapper.when(elWrapper);
        }
    }

    public static void convert(ELWrapper wrapper, Object[] array) {
        if(wrapper instanceof ThenELWrapper){
            ThenELWrapper thenELWrapper = (ThenELWrapper) wrapper;
            thenELWrapper.then(array);
        }else if(wrapper instanceof WhenELWrapper){
            WhenELWrapper whenELWrapper = (WhenELWrapper) wrapper;
            whenELWrapper.when(array);
        }
    }

    public static void convert(ELWrapper wrapper, Object array) {
        if(wrapper instanceof ThenELWrapper){
            ThenELWrapper thenELWrapper = (ThenELWrapper) wrapper;
            thenELWrapper.then(array);
        }else if(wrapper instanceof WhenELWrapper){
            WhenELWrapper whenELWrapper = (WhenELWrapper) wrapper;
            whenELWrapper.when(array);
        }
    }

    /*public static Object getELWrapper(Node node, GraphEL graphEL) throws LiteFlowELException {
        //Map<Long, NodeInfo> nodeInfoMap = graphEL.getNodeInfoMap();
        NodeInfoWrapper nodeInfoWrapper = node.getProperties();
        //Long id = nodeInfoWrapper.getId();
        //if(id != null){
            //NodeInfo nodeInfo = nodeInfoMap.get(id);
            //return NodeInfoToELUtil.toELWrapper(nodeInfo);
        //}
        return NodeInfoToELUtil.buildELWrapper(nodeInfoWrapper);
    }

    public static Object[] nodeSetToArray(GraphEL graphEL) throws LiteFlowELException {
        Set<Node> nodeSet = graphEL.getList().keySet();
        return nodeSet.stream().map(m -> {
            try {
                return getELWrapper(m,graphEL);
            } catch (LiteFlowELException e) {
                throw new RuntimeException(e);
            }
        }).toArray();
    }

    public static Object[] nodeListToArray(List<Node> nodeList,GraphEL graphEL) throws LiteFlowELException {
        if(nodeList == null ){ return null; }
        return nodeList.stream().map(m -> {
            try {
                Object elWrapper = getELWrapper(m, graphEL);
//                if((elWrapper instanceof SwitchELWrapper
//                    || elWrapper instanceof IfELWrapper
//                )
//                        && graphEL.getList().get(m).size() > 1){
//                    return null;
//                }
                return elWrapper;
            } catch (LiteFlowELException e) {
                throw new RuntimeException(e);
            }
        }).filter(Objects::nonNull).toArray();
    }

    public static <T> boolean isPropertyAllEqual(List<T> list, Function<T, Object> getProperty, Object value) {
        return list.stream().allMatch(item -> getProperty.apply(item).equals(value));
    }

    // 获取 分叉节点 -> 聚合节点
    public static List<Node> getForkJoinNode(Node forkNode,Node joinNode,GraphEL graphEL){
        return graphEL.getCommonNodesInAllPaths(forkNode,joinNode);
    }

    //获取 开始节点 -> 结束节点
    public static List<Node> getStartEndNode(Node startNode,Node endNode,GraphEL graphEL){
        Map<Node, List<Node>> map = graphEL.getList();
        List<Node> nodeList = new ArrayList<>();
        if(startNode == endNode || endNode == null){
            nodeList.add(startNode);
        }else{
            while (startNode != endNode){
                nodeList.add(startNode);
                List<Node> list = map.get(startNode);
                if(CommonUtil.collUtil.isNotEmpty(list)){
                    startNode = list.get(0);
                }
                if(graphEL.isEndNode(startNode)){
                    break;
                }
            }
            nodeList.add(endNode);
        }
        return nodeList;
    }


    //流处理List<List<Node>> 获取所有集合中指定Node节点之前的元素
//    public static List<List<Node>> processRemoveGroupNode(List<List<Node>> listOfNodeLists, Node targetNode) {
//        List<Node> removedNodes = new ArrayList<>();
//        Set<Node> uniqueRemovedNodes = new HashSet<>();
//        List<List<Node>> result = listOfNodeLists.stream()
//                .map(nodeList -> {
//                    int index = nodeList.indexOf(targetNode);
//                    if (index != -1) {
//                        List<Node> removed = nodeList.subList(0, index + 1);
//                        uniqueRemovedNodes.addAll(removed);
//                        return nodeList.subList(index, nodeList.size());
//                    } else {
//                        return nodeList;
//                    }
//                })
//                .collect(Collectors.toList());
//
//        removedNodes.addAll(new ArrayList<>(uniqueRemovedNodes));
//        return result;
//    }
    public static List<List<Node>> processRemoveGroupNode(List<List<Node>> listOfNodeLists, Node targetNode) {
        return listOfNodeLists.stream()
                .map(nodeList -> {
                    int index = nodeList.indexOf(targetNode);
                    return index != -1 ? nodeList.subList(0, index) : nodeList;
                })
                .collect(Collectors.toList());
    }

    //流处理List<List<Node>> 将所有集合中指定Node节点之前的都去除
    public static List<List<Node>> processGroupNode(List<List<Node>> listOfNodeLists, Node targetNode) {
        return listOfNodeLists.stream()
                .map(nodeList -> {
                    int index = nodeList.indexOf(targetNode);
                    return index != -1 ? nodeList.subList(index, nodeList.size()) : nodeList;
                })
                .collect(Collectors.toList());
    }

    // 去除相同的结束节点
    public static Map<String,List<List<Node>>> removeLastSameNode(Node startNode, List<List<Node>> allPaths) {
        Map<String,List<List<Node>>> resultMap = new HashMap<>();
        resultMap.put("same", new ArrayList<>());
        Map<Node, List<List<Node>>> groupedPaths = allPaths.stream().collect(Collectors.groupingBy(path -> path.get(path.size() - 1)));
        for (Map.Entry<Node, List<List<Node>>> group : groupedPaths.entrySet()){
            List<List<Node>> value = group.getValue();
            if(value.size() > 1){
                Node prevSameNode = getPrevSameNode(startNode, value);
                List<List<Node>> lists = processGroupNode(value, prevSameNode);
                List<List<Node>> excludeList = processRemoveGroupNode(value, prevSameNode);
                resultMap.get("same").addAll(excludeList);
                List<List<Node>> reversedPathList = lists.stream()
                        .map(subList -> {
                            Collections.reverse(subList);
                            return subList;
                        }).collect(Collectors.toList());
                group.setValue(reversedPathList);
            }
        }

        List<List<Node>> listList = groupedPaths.values().stream()
                .flatMap(List::stream)
                .collect(Collectors.toList());
        resultMap.put("noSame",listList);
        return resultMap;
    }

    public static Node getPrevSameNode(Node startNode, List<List<Node>> pathList) {
        // 使用Stream和Collections.reverse倒序集合
        List<List<Node>> reversedPathList = pathList.stream()
                .map(subList -> {
                    Collections.reverse(subList);
                    return subList;
                }).collect(Collectors.toList());
        int index = 0;
        return findCommonNode(index, reversedPathList);
    }

    private static Node findCommonNode(Integer index, List<List<Node>> pathList) {
        Integer finalIndex = index;
        boolean allSecondElementsEqual = pathList.stream()
                .map(subList -> subList.size() > 1 ? subList.get(finalIndex) : null) // 获取第二个元素，如果存在的话
                .distinct() // 去重
                .count() <= 1; // 如果去重后的数量不超过1，则表示全部相同
        if(allSecondElementsEqual){
            index++;
            return findCommonNode(index, pathList);
        }
        return pathList.get(0).get(finalIndex - 1);
    }

    // 获取路径共同的分叉节点
    public static List<Node> getPrevForkNode(Node current, Map<Node, List<List<Node>>> map, GraphEL graphEL) {
        Map<Node, List<Node>> ascMap = graphEL.getList();
        Map<Node, List<Node>> descMap = graphEL.getReverseList();
        List<Node> list = new ArrayList<>();
        for (Map.Entry<Node, List<List<Node>>> group : map.entrySet()){
            list.add(getPrevForkNode(group.getKey(), group.getValue(), ascMap, descMap));
        }
        list = list.stream().distinct().collect(Collectors.toList());
        // 如果分叉节点是current的父节点，则去除
        Iterator<Node> iterator = list.iterator();
        while (iterator.hasNext()) {
            Node node = iterator.next();
            if(node != current){
                boolean flag = graphEL.isParentNode(current, node);
                if(flag){
                    iterator.remove();
                }
            }
        }
        return list.stream().filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static Node getPrevForkNode(Node node, List<List<Node>> pathList, Map<Node, List<Node>> ascMap, Map<Node, List<Node>> descMap) {
        Node node1 = null;
        if(pathList.size() > 1){
            List<Node> nodeList = pathList.stream().map(m -> m.get(0)).distinct().collect(Collectors.toList());
            Set<Node> nodeSet = new HashSet<>();
            for (Node item : nodeList){
                List<List<Node>> pathLists = pathList.stream().filter(m -> m.contains(item)).collect(Collectors.toList());
                Node prevForkNode = getPrevForkNode(item, pathLists.subList(0, 1), ascMap, descMap);
                if(prevForkNode != null){
                    nodeSet.add(prevForkNode);
                }
            }
            if(nodeSet.size() > 1){
                throw new RuntimeException("获取分叉节点异常！");
            }
            return nodeSet.stream().findFirst().orElse(null);
        }else{
            List<Node> nodeList = descMap.get(node);
            if(CollUtil.isNotEmpty(nodeList)){
                node1 = nodeList.get(0);
                if(ascMap.get(node1).size() > 1){
                    return node1;
                }
            }else{
                return null;
            }
        }
        return getPrevForkNode(node1, pathList, ascMap, descMap);
    }


    //allPaths 中的节点只要在excludeNodeList 中存在就去除
    public static List<List<Node>> filterPaths(List<List<Node>> allPaths, List<Node> excludeNodeList) {
        Set<Node> excludeSet = new HashSet<>(excludeNodeList);

        return allPaths.stream()
                .map(path -> path.stream()
                        .filter(node -> !excludeSet.contains(node))
                        .collect(Collectors.toList()))
                .collect(Collectors.toList());
    }

    // 判断路径是否有交集
    public static boolean isPathSameNode(Map<Node, List<List<Node>>> groupedPaths, Node node){
        List<Node> list1 = groupedPaths.entrySet().stream().filter(m -> m.getKey().equals(node)).map(m -> m.getValue())
                .flatMap(List::stream)
                .collect(Collectors.toList()).stream().flatMap(List::stream).collect(Collectors.toList());

        List<Node> list2 = groupedPaths.entrySet().stream().filter(m -> !m.getKey().equals(node)).map(m -> m.getValue())
                .flatMap(List::stream)
                .collect(Collectors.toList()).stream().flatMap(List::stream).collect(Collectors.toList());

        return list1.stream().anyMatch(list2::contains);
    }*/
}
